package xyz.lwm.lazycat.beans;

import lombok.AllArgsConstructor;
import xyz.lwm.lazycat.aop.AopUtil;
import xyz.lwm.lazycat.setting.Setting;
import xyz.lwm.lazycat.utility.CollectionUtil;
import xyz.lwm.lazycat.utility.It;
import xyz.lwm.lazycat.utility.reflect.ReflectUtil;

/**
 * 注入属性
 *
 * @author lwm
 */
@AllArgsConstructor
class BeanPostProcessorForInjection implements BeanPostProcessor {

    private final BeanDesignRegistry registry;

    private final BeanRefs beanRefs;

    private final Beans beans;

    private final Setting setting;

    /**
     * 注入属性
     *
     * @param bean bean 对象
     * @param beanName bean 名称
     * @return bean 对象
     */
    @Override
    public Object processBeforeInitialization(Object bean, String beanName) throws BeansException {
        BeanDesign<?> design = registry.getDesign(beanName);

        It.of(design.getInjections()).filter(CollectionUtil::isNotEmpty).also(injections -> {
            for (Injection injection : injections) {
                // 获取注入的 bean
                Object injectedBean = getInjectedBean(injection);
                // 解包装 bean, 获取未被代理的 bean, 即原始 bean
                Object unwrapped = AopUtil.unwrap(bean);
                // 设置属性
                ReflectUtil.setValue(unwrapped, injection.getProperty(), injectedBean);
            }
        });

        return BeanPostProcessor.super.processBeforeInitialization(bean, beanName);
    }

    /**
     * 允许注入 {@link BeanDesignRegistry} {@link Beans} {@link Setting}
     *
     * @param injection injection
     * @return injected bean
     */
    private Object getInjectedBean(Injection injection) {
        if (injection.getType() == BeanDesignRegistry.class) {
            return registry;
        } else if (injection.getType() == Beans.class) {
            return beans;
        } else if (injection.getType() == Setting.class) {
            return setting;
        } else  {
            return injection.apply(beanRefs);
        }
    }

    @Override
    public Object processAfterInitialization(Object bean, String beanName) throws BeansException {
        return BeanPostProcessor.super.processAfterInitialization(bean, beanName);
    }

}
